using System;
using System.Collections.Generic;

namespace Picnic.Spec.Console
{
	/// <summary>
	/// Represents a simple system console (System.Console).
	/// </summary>
	public class SystemConsole : IConsole
	{
		private readonly Stack<ConsoleColor> _previousColors = new Stack<ConsoleColor>();
		private readonly int _padding;
		private readonly int _paddingStep;

		/// <summary>
		/// Initializes a new instance of the <see cref="T:System.Object"/> class.
		/// </summary>
		public SystemConsole(int padding = 0, int paddingStep = 2)
		{
			_padding = padding;
			_paddingStep = paddingStep;
		}

		/// <summary>
		/// Gets a console width.
		/// </summary>
		public int Width
		{
			get { return System.Console.WindowWidth; }
		}

		/// <summary>
		/// Gets a console hight.
		/// </summary>
		public int Height
		{
			get { return System.Console.WindowHeight; }
		}

		/// <summary>
		/// Sets console color.
		/// </summary>
		public void SetColor(ConsoleColor color)
		{
			_previousColors.Push(System.Console.ForegroundColor);
			System.Console.ForegroundColor = color;
		}

		/// <summary>
		/// Undo console color changed by <see cref="IConsole.SetColor"/> command.
		/// </summary>
		public void UndoColor()
		{
			if (_previousColors.Count == 0)
			{
				return;
			}
			System.Console.ForegroundColor = _previousColors.Pop();
		}

		/// <summary>
		/// Writes empty line.
		/// </summary>
		public void WriteLine()
		{
			System.Console.WriteLine();
		}

		/// <summary>
		/// Writes message.
		/// </summary>
		public void WriteLine(string message)
		{
			WriteLine(message, _padding, _paddingStep, true);
		}

		/// <summary>
		/// Writes message with specified padding.
		/// </summary>
		public void WriteLine(string message, int padding)
		{
			WriteLine(message, _padding + padding, _paddingStep, true);
		}

		private static void WriteLine(string message, int paddingLeft, int paddingStep, bool start)
		{
			message = message.Replace("\r\n", string.Empty);
			if (!start)
			{
				message = message.Trim();
			}

			var linePadding = start ? (paddingLeft + paddingStep + GetLinePadding(message)) : paddingLeft;
			var lineLenght = message.Length + paddingLeft;
			if (lineLenght < System.Console.WindowWidth)
			{
				System.Console.WriteLine(message.PadLeft(lineLenght, ' '));
				return;
			}
			if (lineLenght == System.Console.WindowWidth)
			{
				System.Console.Write(message.PadLeft(lineLenght, ' '));
				return;
			}

			var subStringLength = System.Console.WindowWidth - paddingLeft;
			var subString = message.Substring(0, subStringLength);
			System.Console.Write(subString.PadLeft(System.Console.WindowWidth, ' '));

			var tail = message.Substring(subString.Length);
			WriteLine(tail, linePadding, paddingStep, false);
		}

		private static int GetLinePadding(string line)
		{
			for (var i = 0; i < line.Length; i++)
			{
				if (line[i] != ' ')
					return i;
			}
			return line.Length;
		}
	}
}